package org.shagin.jfin.ui.budget.item;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.text.ParseException;
import java.util.Collections;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;

import org.shagin.jfin.core.CoreUtils;
import org.shagin.jfin.core.Debug;
import org.shagin.jfin.core.ui.JJDialog;
import org.shagin.jfin.data.model.IBudget;
import org.shagin.jfin.data.model.OperationRule;
import org.shagin.jfin.data.model.OperationRuleAction;
import org.shagin.jfin.data.util.CurrencyUtil;
import org.shagin.jfin.data.util.MoneyUtil;
import org.shagin.jfin.date.cond.Never;
import org.shagin.jfin.ui.UI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The Class JOperationRuleActionsPane.
 */
@SuppressWarnings("serial")
public class JOperationRuleActionsPane extends JPanel {

    private static final Logger log = LoggerFactory
            .getLogger(JOperationRuleActionsPane.class);

    private JTable table = new JTable();
    private ActionsTableModel tableModel = new ActionsTableModel();
    private OperationRule operationRule;
    private static final List<OperationRuleAction> EMPTY = Collections
            .emptyList();
    private JButton btnAdd = new JButton();
    private JButton btnDelete = new JButton();
    private JButton btnEdit = new JButton();

    /**
     * The Class ActionsTableModel.
     */
    private class ActionsTableModel extends AbstractTableModel {

        /**
         * {@inheritDoc}
         */
        @Override
        public int getRowCount() {
            return getActions().size();
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public int getColumnCount() {
            return 2;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            OperationRuleAction action = getActions().get(rowIndex);
            return (columnIndex == 0 ? action.getDateCondition() : action
                    .getMoney());
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
            Debug.traceEnter(log);
            if (columnIndex == 1) {
                OperationRuleAction action = getActions().get(rowIndex);
                try {
                    double newValue = CurrencyUtil.parse(aValue.toString());
                    double oldValue = action.getMoney().getValue();
                    if (newValue != oldValue) {
                        action.getMoney().setValue(newValue);
                        if (getBudget() != null) {
                            getBudget().fireOperationRuleChangedEvent(
                                    getOperationRule());
                        }
                    }
                } catch (ParseException ignore) {
                }
            }
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public String getColumnName(int column) {
            // TODO Localize
            return (column == 0 ? "Когда" : "Сколько");
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            return columnIndex == 1;
        }
    }

    /**
     * Instantiates a new j operation rule actions pane.
     */
    public JOperationRuleActionsPane() {
        super();
        setLayout(new BorderLayout());
        JScrollPane scrollPane = new JScrollPane(table);
        add(createToolbar(), BorderLayout.NORTH);
        add(scrollPane, BorderLayout.CENTER);
        table.setModel(tableModel);
        initEvents();
    }

    private JPanel createToolbar() {
        JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, UI.HGAP,
                UI.VGAP));
        // TODO Localize
        btnAdd.setText("Add");
        btnDelete.setText("Delete");
        btnEdit.setText("Edit");
        btnAdd.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                addOperationRuleActionUI();
            }
        });
        btnDelete.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                deleteSelectedRowUI();
            }
        });
        btnEdit.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                editSelectedRowUI();
            }
        });
        panel.add(btnAdd);
        panel.add(btnDelete);
        panel.add(btnEdit);
        return panel;
    }

    private OperationRuleAction newOperationRuleAction() {
        OperationRuleAction result = new OperationRuleAction(new Never(),
                MoneyUtil.zero(getBudget().getDefaultCurrency()));
        result.setOperationRule(getOperationRule());
        return result;
    }

    private void addOperationRuleAction(OperationRuleAction operationRuleAction) {
        CoreUtils.assertNotNull(operationRule, "operationRule");
        operationRule.add(operationRuleAction);
    }

    /**
     * Adds the operation rule action ui.
     */
    private void addOperationRuleActionUI() {
        Debug.traceEnter(log);
        OperationRuleAction newOperationRuleAction = newOperationRuleAction();
        addOperationRuleAction(newOperationRuleAction);
        JOperationRuleActionDialog dialog = new JOperationRuleActionDialog(
                newOperationRuleAction);
        if (dialog.showModal() != JJDialog.MODAL_RESULT_OK) {
            delete(newOperationRuleAction);
            fireOperationRuleChangedEvent();
        };
        updateTableUI();
    }

    /**
     * Edits the.
     * 
     * @param operationRuleAction the operation rule action
     */
    private void edit(OperationRuleAction operationRuleAction) {
        Debug.traceEnter(log);
        CoreUtils.checkNotNull(operationRuleAction, "operationRuleAction");
        new JOperationRuleActionDialog(operationRuleAction).setVisible(true);
    }

    /**
     * Edits the selected row ui.
     */
    private void editSelectedRowUI() {
        OperationRuleAction row = getSelectedRow();
        if (row != null) {
            edit(row);
        }
        updateTableUI();
    }

    private void delete(OperationRuleAction operationRuleAction) {
        Debug.traceEnter(log);
        CoreUtils.checkNotNull(operationRuleAction, "operationRuleAction");
        operationRule.remove(operationRuleAction);
    }

    /**
     * Delete selected row ui.
     */
    private void deleteSelectedRowUI() {
        OperationRuleAction row = getSelectedRow();
        if (row != null) {
            delete(row);
            fireOperationRuleChangedEvent();
            updateTableUI();
        }
    }

    /**
     * Fire operation rule changed event.
     */
    private void fireOperationRuleChangedEvent() {
        Debug.traceEnter(log);
        getBudget().fireOperationRuleChangedEvent(operationRule);
    }

    /**
     * Inits the events.
     */
    private void initEvents() {
        table.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                if (e.getClickCount() == 2) {
                    editSelectedRowUI();
                }
            }
        });
    }

    /**
     * Gets the selected row.
     * 
     * @return the selected row
     */
    private OperationRuleAction getSelectedRow() {
        OperationRuleAction result = null;
        if (!getActions().isEmpty()) {
            int rowIndex = table.getSelectedRow();
            if (rowIndex != -1)
                result = getActions().get(rowIndex);
        }
        return result;
    }

    /**
     * Gets the actions.
     * 
     * @return the actions
     */
    private List<OperationRuleAction> getActions() {
        return operationRule == null ? EMPTY : operationRule.getActions();
    }

    /**
     * Gets the budget.
     * 
     * @return the budget
     */
    private IBudget getBudget() {
        return getOperationRule().getBudget();
    }

    /**
     * Gets the operation rule.
     * 
     * @return the operation rule
     */
    private OperationRule getOperationRule() {
        CoreUtils.assertNotNull(operationRule, "operationRule");
        return operationRule;
    }

    /**
     * Sets the operation rule.
     * 
     * @param operationRule the new operation rule
     */
    public void setOperationRule(OperationRule operationRule) {
        this.operationRule = operationRule;
        updateTableUI();
    }

    /**
     * Update table ui.
     */
    private void updateTableUI() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                table.updateUI();
            }
        });
    }
}
